package com.cy.common.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.cy.common.annotation.SysLogAnnotation;
import com.cy.common.util.IPUtils;
import com.cy.common.util.ShiroUtil;
import com.cy.sys.pojo.SysLog;
import com.cy.sys.service.SysLogService;
import com.fasterxml.jackson.databind.ObjectMapper;

import lombok.extern.slf4j.Slf4j;

/**
 * 此切面类负责抽取记录日志的共性
 * @author private
 *
 */
@Aspect //定义此类为一个切入点
@Slf4j
@Component //将此切入点类交由Spring进行管理
public class SysLogAspect {
	
	//定义切入点为整个userService类
	@Pointcut("bean(sysUserService)")
	public void doSysLog() {}
	
	//定义切入点要执行的方法
	@Around("doSysLog()")
	public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
		long start = System.currentTimeMillis();
		String classMethodName = doGetInvokeClassMethodName(joinPoint);
		try {
			System.out.println("???????");
			Object proceed = joinPoint.proceed();
			long end = System.currentTimeMillis();
			long time = end-start;
			log.info("执行<{}>方法,总耗时{}秒",classMethodName,time);
			//启动异步日志记录,将日志信息写入数据库
			doSysLogging(joinPoint,time);
			return proceed;
		} catch (Throwable e) {
			log.debug("执行<{}>方法出现异常:{}",classMethodName,e.getMessage());
			throw e;
		}
	}
	
	@Autowired
	private SysLogService sysLogService;
	
	/** 此方法负责将日志信息写入到数据库  */
	public void doSysLogging(ProceedingJoinPoint joinPoint,long time) throws Exception{
		//1.获取执行操作的用户(username)
		String username = ShiroUtil.getUserName();
		//2.获取执行的操作(operation)
		MethodSignature signature = (MethodSignature)joinPoint.getSignature();
		String methodName = signature.getMethod().getName();
		Class<?>[] parameterTypes = signature.getParameterTypes();
		SysLogAnnotation log = joinPoint.getTarget().getClass().getMethod(methodName, parameterTypes).getAnnotation(SysLogAnnotation.class);
		String operation;
		if(log!=null) operation = log.methodName();
			else operation = "operation";
		//3.获取执行方法的全类名(method)
		String method = doGetInvokeClassMethodName(joinPoint);
		//4.获取执行方法所传的参数
		String args = new ObjectMapper().writeValueAsString(joinPoint.getArgs());
		//5.获取ip地址
		String ip = IPUtils.getIpAddr();
		//6.封装为SysLog对象,执行写入数据库
		SysLog sysLog = new SysLog();
		sysLog.setUsername(username).setOperation(operation).setMethod(method).setParams(args)
			.setTime((int)time).setIp(ip);
		sysLogService.addLog(sysLog);
	}
	
	
	public String doGetInvokeClassMethodName(ProceedingJoinPoint joinPoint) {
		MethodSignature ms = (MethodSignature) joinPoint.getSignature();
		String className = ms.getDeclaringTypeName();
		String methodName = ms.getName();
		return className+"."+methodName;
	}
	
	
}
